package top.drose.entity;

import com.alibaba.fastjson2.JSON;
import top.drose.service.CalculateMethod;
import top.drose.service.CalculateMethod_1;

import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

//答题卡类
public class QuestionSheet implements Serializable {
    //试卷id
    private String id;
    //试卷名称
    private String name;
    //创建日期
    private Date date;
    //是否是历史记录,默认不是
    private Boolean isHistory=Boolean.FALSE;
    //单选题
    //正确答案
    LinkedList<Character> singleCorrectAnswers;
    //学生的答案
    LinkedList<Character> singleResponse;
    //答案是否正确
    LinkedList<Boolean> singleJudgeResult;
    Double singleTotalScore;
    //多选题
    LinkedList<String> multiCorrectAnswers;
    LinkedList<String> multiResponse;
    LinkedList<Double> multiJudgeResult;
    Double multipleTotalScore;
    //分数
    double totalScore;
    //配置（题目个数，分数计算方式）
    Integer singleNumber=50;
    Integer multipleNumber=30;
    Integer singleScore=1;
    Integer multipleScore=2;
    final Integer formatLength=6;


    //后缀,用来将文本颜色还原为默认值
    final String RESET = "\u001B[0m";
    //下面三个是前缀
    final String BLACK = "\u001B[30m";
    final String RED = "\u001B[31m";
    final String GREEN = "\u001B[32m";
    //输出格式为str=RED + "这是红色的文字" + RESET





    public QuestionSheet(String id){
        this.id = id;
        this.singleCorrectAnswers = new LinkedList<>();
        this.singleResponse = new LinkedList<>();
        this.singleJudgeResult = new LinkedList<>();
        this.singleTotalScore = 0.0;

        this.multiCorrectAnswers = new LinkedList<>();
        this.multiResponse = new LinkedList<>();
        this.multiJudgeResult = new LinkedList<>();
        this.multipleTotalScore = 0.0;
        //题目个数
        this.singleNumber = 5;
        this.multipleNumber = 5;
        //题目分数
        this.singleScore = 1;
        this.multipleScore = 2;
        //总分数
        this.totalScore = 0.0;
    }
    private void formattedSpace(int length){
        for(int i=0;i<length;i++){
            System.out.printf(" ");
        }
    }

    public void show(){
        int index=1;
        System.out.println("-----"+this.name+"-----     q结束答题|s保存答案");
        int rows = 3; // 每次输出3行
        int elementsPerLine = 10; // 每行输出5个元素

        // 计算总共有多少组3行需要输出
        double temp = 1.0*singleNumber / elementsPerLine;
        int totalGroups=(int)Math.ceil(temp);
        System.out.println("单选题");
        int question=1;
        int answerIndex=0;
        int responseIndex=0;
        for(int group=0;group<totalGroups;group++){//以三行为单位的一个大行
            for(int row=0;row<rows;row++){//三行中的每一行
                for(int i=0;i<elementsPerLine;i++){//每行的元素个数
                    if(answerIndex>=singleNumber){
                        break;
                    }
                    if(row==0){
                        if(question>singleNumber){
                            formattedSpace(formatLength);
                        }else{
                            System.out.printf("%"+this.formatLength+"d",question);
                            question++;
                        }
                    }else if(row==2){
//                        System.out.printf("%4c",singleCorrectAnswers.get(answerIndex++));
                    }else{
                        //这里如果没有输入，就不要get，而是给个空
                        if(responseIndex<singleResponse.size()){
                            System.out.printf("%"+formatLength+"c",singleResponse.get(responseIndex++));
                        }else{
                            formattedSpace(formatLength);
                        }
                    }
                }
                System.out.println();
            }
        }

        index=question;
        System.out.println("多选题");
        temp = 1.0*multipleNumber / elementsPerLine;
        totalGroups=(int)Math.ceil(temp);
        question=1;//题号
        answerIndex=0;
        responseIndex=0;
        for(int group=0;group<totalGroups;group++){//以三行为单位的一个大行
            for(int row=0;row<rows;row++){//三行中的每一行
                for(int i=0;i<elementsPerLine;i++){//每行的元素个数
                    if(answerIndex>=multipleNumber){
                        break;
                    }
                    if(row==0){
                        if(question>multipleNumber){
                            formattedSpace(4);
                        }else{
                            //题号和question号码同时增加
                            System.out.printf("%"+formatLength+"d",index++);
                            question++;
                        }
                    }else if(row==2){
//                        System.out.printf("%4c",singleCorrectAnswers.get(answerIndex++));
                    }else{
                        //这里如果没有输入，就不要get，而是给个空
                        if(responseIndex<multiResponse.size()){
                            String out=String.format("%"+formatLength+"s",multiResponse.get(responseIndex++));
                            System.out.printf("%s",out);
                        }else{
                            formattedSpace(formatLength);
                        }
                    }
                }
                System.out.println();
            }
        }
    }

    //兼容之前的空参方法,空参展示的是非历史记录
    public void showResult(){
        this.showResult(Optional.of(false));
    }
        //现实结果，这里要现实正确的和不正确的区别
    public void showResult(Optional<Boolean> history){
        double score=this.calculateTotalScore();
        int rows = 3; // 每次输出3行
        int elementsPerLine = 10; // 每行输出5个元素

        // 计算总共有多少组3行需要输出
        double temp = 1.0*singleNumber / elementsPerLine;
        int totalGroups=(int)Math.ceil(temp);
        System.out.println("单选题");
        int question=1;
        int answerIndex=0;
        int responseIndex=0;
        for(int group=0;group<totalGroups;group++){//以三行为单位的一个大行
            for(int row=0;row<rows;row++){//三行中的每一行
                for(int i=0;i<elementsPerLine;i++){//每行的元素个数
                    if(answerIndex>=singleNumber){
                        break;
                    }
                    if(row==0){
                        if(question>singleNumber){
                            formattedSpace(formatLength);
                        }else{
                            System.out.printf("%"+this.formatLength+"d",question);
                            System.out.flush();

                            question++;
                        }
                    }else if(row==2){
                        System.out.printf("%"+formatLength+"c",singleCorrectAnswers.get(answerIndex++));
                        System.out.flush();

                    }else{
                        //这里如果没有输入，就不要get，而是给个空
                        if(responseIndex<singleResponse.size()){
                            if(singleJudgeResult.get(responseIndex)==true){//表示正确
                                System.out.printf("%"+formatLength+"c",singleResponse.get(responseIndex++));
                                System.out.flush();

                            }else{//回答错误
                                System.out.printf(RED+"%"+formatLength+"c"+RESET,singleResponse.get(responseIndex++));
                                System.out.flush();

                            }
                        }else{
                            formattedSpace(formatLength);
                        }
                    }
                }
                System.out.println();
            }
        }
        System.out.println("多选题");
        temp = 1.0*multipleNumber / elementsPerLine;
        totalGroups=(int)Math.ceil(temp);
        question=1;
        answerIndex=0;
        responseIndex=0;
        for(int group=0;group<totalGroups;group++){//以三行为单位的一个大行
            for(int row=0;row<rows;row++){//三行中的每一行
                for(int i=0;i<elementsPerLine;i++){//每行的元素个数
                    if(answerIndex>=multipleNumber){
                        break;
                    }
                    if(row==0){
                        if(question>multipleNumber){
                            formattedSpace(formatLength);
                        }else{
                            System.out.printf("%"+formatLength+"d",question);
                            question++;
                        }
                    }else if(row==2){//输出正确答案
                        String out=String.format("%"+formatLength+"s",multiCorrectAnswers.get(answerIndex++));
                        System.out.printf("%s",out);
                        System.out.flush();
                    }else{
                        //这里如果没有输入，就不要get，而是给个空
                        if(responseIndex<multiResponse.size()){
                            if(multiJudgeResult.get(responseIndex)==0.0){//0分就把学生的选项标红
                                String out=String.format(RED+"%"+formatLength+"s"+RESET,multiResponse.get(responseIndex++));
                                System.out.printf("%s",out);
                                System.out.flush();
                            }else if(multiJudgeResult.get(responseIndex)!=(1.0)*multipleScore){//不是满分
                                String out=String.format(GREEN+"%"+formatLength+"s"+RESET,multiResponse.get(responseIndex++));
                                System.out.printf("%s",out);
                                System.out.flush();
                            }else{//满分,就正常输出
                                String out=String.format("%"+formatLength+"s",multiResponse.get(responseIndex++));
                                System.out.printf("%s",out);
                                System.out.flush();
                            }
                        }else{
                            formattedSpace(formatLength);
                        }
                    }
                }
                System.out.println();
            }
        }
        System.out.println("你的成绩是："+score);


    }


    public double calculateTotalScore(){
        double temp=0;

        for(int i=0;i<singleNumber;i++){
            //保证对比的一致性，都转换为小写比较
            char csa = Character.toLowerCase(singleCorrectAnswers.get(i));
            char sr = Character.toLowerCase(singleResponse.get(i));
            if(csa==sr){
                singleJudgeResult.add(true);
                temp+=singleScore;
            }else{
                singleJudgeResult.add(false);
            }
        }
        singleTotalScore=temp;
        //多选题的判断方法
        //多选（用红色给出？）  少选用绿色给出
        temp=0;
        for(int i=0;i<multipleNumber;i++){
            multiJudgeResult.add(0.0);
        }
        for(int i=0;i<multipleNumber;i++){
            //给选项排序
            byte[] bytes = multiResponse.get(i).getBytes();
            Arrays.sort(bytes);
            multiResponse.set(i,new String(bytes));

            //如果完全相等，则正确，给满分
            CalculateMethod c=new CalculateMethod_1();
            //都转换为小写比较
            double res=c.calculateMultiScore(
                    multiCorrectAnswers.get(i).toLowerCase(),
                    multiResponse.get(i).toLowerCase());
            temp+=res;
            multiJudgeResult.set(i,res);
        }
        multipleTotalScore=temp;
        totalScore=singleTotalScore+multipleTotalScore;
        return totalScore;
    }

    public void save(String preDir){
        //执行保存操作
        System.out.println("正在保存...");
        this.setDate(new Date());
        this.setName("history_"+this.getName()+"_"+this.getDate().toString());
        this.setHistory(true);

        String jsonString = JSON.toJSONString(this);
        String f= preDir+"\\"+ this.getId() + "_history_"+this.getDate().getTime()+ ".json";
        try {
            //指定utf-8写入数据
            Files.write(Paths.get(f), Collections.singletonList(jsonString), StandardCharsets.UTF_8);
            System.out.println("保存成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public QuestionSheet(String id, String name, Date date, Boolean isHistory, LinkedList<Character> singleCorrectAnswers, LinkedList<Character> singleResponse, LinkedList<Boolean> singleJudgeResult, Double singleTotalScore, LinkedList<String> multiCorrectAnswers, LinkedList<String> multiResponse, LinkedList<Double> multiJudgeResult, Double multipleTotalScore, double totalScore, Integer singleNumber, Integer multipleNumber, Integer singleScore, Integer multipleScore) {
        this.id = id;
        this.name = name;
        this.date = date;
        this.isHistory = isHistory;
        this.singleCorrectAnswers = singleCorrectAnswers;
        this.singleResponse = singleResponse;
        this.singleJudgeResult = singleJudgeResult;
        this.singleTotalScore = singleTotalScore;
        this.multiCorrectAnswers = multiCorrectAnswers;
        this.multiResponse = multiResponse;
        this.multiJudgeResult = multiJudgeResult;
        this.multipleTotalScore = multipleTotalScore;
        this.totalScore = totalScore;
        this.singleNumber = singleNumber;
        this.multipleNumber = multipleNumber;
        this.singleScore = singleScore;
        this.multipleScore = multipleScore;
    }

    public QuestionSheet() {

    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Boolean getHistory() {
        return isHistory;
    }

    public void setHistory(Boolean history) {
        isHistory = history;
    }

    public LinkedList<Character> getSingleCorrectAnswers() {
        return singleCorrectAnswers;
    }

    public void setSingleCorrectAnswers(LinkedList<Character> singleCorrectAnswers) {
        this.singleCorrectAnswers = singleCorrectAnswers;
    }

    public LinkedList<Character> getSingleResponse() {
        return singleResponse;
    }

    public void setSingleResponse(LinkedList<Character> singleResponse) {
        this.singleResponse = singleResponse;
    }

    public LinkedList<Boolean> getSingleJudgeResult() {
        return singleJudgeResult;
    }

    public void setSingleJudgeResult(LinkedList<Boolean> singleJudgeResult) {
        this.singleJudgeResult = singleJudgeResult;
    }

    public Double getSingleTotalScore() {
        return singleTotalScore;
    }

    public void setSingleTotalScore(Double singleTotalScore) {
        this.singleTotalScore = singleTotalScore;
    }

    public LinkedList<String> getMultiCorrectAnswers() {
        return multiCorrectAnswers;
    }

    public void setMultiCorrectAnswers(LinkedList<String> multiCorrectAnswers) {
        this.multiCorrectAnswers = multiCorrectAnswers;
    }

    public LinkedList<String> getMultiResponse() {
        return multiResponse;
    }

    public void setMultiResponse(LinkedList<String> multiResponse) {
        this.multiResponse = multiResponse;
    }

    public LinkedList<Double> getMultiJudgeResult() {
        return multiJudgeResult;
    }

    public void setMultiJudgeResult(LinkedList<Double> multiJudgeResult) {
        this.multiJudgeResult = multiJudgeResult;
    }

    public Double getMultipleTotalScore() {
        return multipleTotalScore;
    }

    public void setMultipleTotalScore(Double multipleTotalScore) {
        this.multipleTotalScore = multipleTotalScore;
    }

    public double getTotalScore() {
        return totalScore;
    }

    public void setTotalScore(double totalScore) {
        this.totalScore = totalScore;
    }

    public Integer getSingleNumber() {
        return singleNumber;
    }

    public void setSingleNumber(Integer singleNumber) {
        this.singleNumber = singleNumber;
    }

    public Integer getMultipleNumber() {
        return multipleNumber;
    }

    public void setMultipleNumber(Integer multipleNumber) {
        this.multipleNumber = multipleNumber;
    }

    public Integer getSingleScore() {
        return singleScore;
    }

    public void setSingleScore(Integer singleScore) {
        this.singleScore = singleScore;
    }

    public Integer getMultipleScore() {
        return multipleScore;
    }

    public void setMultipleScore(Integer multipleScore) {
        this.multipleScore = multipleScore;
    }

    public Integer getFormatLength() {
        return formatLength;
    }

    public String getRESET() {
        return RESET;
    }

    public String getBLACK() {
        return BLACK;
    }

    public String getRED() {
        return RED;
    }

    public String getGREEN() {
        return GREEN;
    }
}
